#include <libseminix/client/ipc.h>
#include <libseminix/syscall.h>

int seminix_set_badge(int ep, int parent, unsigned long badge)
{
    return __syscall(SYS_seminix_SetBadge, ep, parent, badge);
}

int seminix_send(int ep, seminix_message_t mess)
{
    return __syscall(SYS_seminix_SendIPC, ep, mess, IPC_SEND, NULL, NULL);
}

int seminix_send_timeout(int ep, seminix_message_t mess, struct timespec *ts)
{
    struct timespec time;

    if (!ts)
        return -SERRNO_EINVAL;

    time.tv_sec = ts->tv_sec;
    time.tv_nsec = ts->tv_nsec;

    return __syscall(SYS_seminix_SendIPC, ep, mess, IPC_SEND, NULL, &time);
}

int seminix_nbsend(int ep, seminix_message_t mess)
{
    return __syscall(SYS_seminix_SendIPC, ep, mess, IPC_NBSEND, NULL, NULL);
}

int seminix_send_reply(int ep, seminix_message_t send_mess, seminix_message_t *recv_mess)
{
    int ret;
    seminix_message_t mess;

    ret = __syscall(SYS_seminix_SendIPC, ep, send_mess, IPC_SEND_REPLY, &mess, NULL);
    if (ret)
        return ret;

    if (recv_mess)
        *recv_mess = mess;
    return ret;
}

int seminix_send_reply_timeout(int ep, seminix_message_t send_mess,
    seminix_message_t *recv_mess,  struct timespec *ts)
{
    int ret;
    seminix_message_t mess;
    struct timespec time;

    if (!ts)
        return -SERRNO_EINVAL;

    time.tv_sec = ts->tv_sec;
    time.tv_nsec = ts->tv_nsec;

    ret = __syscall(SYS_seminix_SendIPC, ep, send_mess, IPC_SEND_REPLY, &mess, &time);
    if (ret)
        return ret;

    if (recv_mess)
        *recv_mess = mess;
    return ret;
}

int seminix_nbsend_reply(int ep, seminix_message_t send_mess, seminix_message_t *recv_mess)
{
    int ret;
    seminix_message_t mess;

    ret = __syscall(SYS_seminix_SendIPC, ep, send_mess, IPC_NBSEND_REPLY, &mess, NULL);
    if (ret)
        return ret;

    if (recv_mess)
        *recv_mess = mess;
    return ret;
}

int seminix_nbsend_reply_timeout(int ep, seminix_message_t send_mess,
    seminix_message_t *recv_mess, struct timespec *ts)
{
    int ret;
    seminix_message_t mess;
    struct timespec time;

    if (!ts)
        return -SERRNO_EINVAL;

    time.tv_sec = ts->tv_sec;
    time.tv_nsec = ts->tv_nsec;

    ret = __syscall(SYS_seminix_SendIPC, ep, send_mess, IPC_NBSEND_REPLY, &mess, &time);
    if (ret)
        return ret;

    if (recv_mess)
        *recv_mess = mess;
    return ret;
}

int seminix_notify(int ep, seminix_message_t mess)
{
    return __syscall(SYS_seminix_SendIPC, ep, mess, IPC_SEND_NOTIFY, NULL, NULL);
}

int seminix_recv(int ep, bool *reply, unsigned long *badge, seminix_message_t *mess)
{
    int ret;
    bool rep;
    unsigned long sender;
    seminix_message_t recv_mess;

    ret = __syscall(SYS_seminix_RecvIPC, ep, IPC_RECV, &recv_mess, &rep, &sender, NULL);
    if (ret)
        return ret;

    if (reply)
        *reply = rep;
    if (badge)
        *badge = sender;
    if (mess)
        *mess = recv_mess;
    return ret;
}

int seminix_recv_timeout(int ep, bool *reply, unsigned long *badge, seminix_message_t *mess, struct timespec *ts)
{
    int ret;
    bool rep;
    unsigned long sender;
    seminix_message_t recv_mess;
    struct timespec time;

    if (!ts)
        return -SERRNO_EINVAL;

    time.tv_sec = ts->tv_sec;
    time.tv_nsec = ts->tv_nsec;

    ret = __syscall(SYS_seminix_RecvIPC, ep, IPC_RECV, &recv_mess, &rep, &sender, &time);
    if (ret)
        return ret;

    if (reply)
        *reply = rep;
    if (badge)
        *badge = sender;
    if (mess)
        *mess = recv_mess;
    return ret;
}

int seminix_nbrecv(int ep, bool *reply, unsigned long *badge, seminix_message_t *mess)
{
    int ret;
    bool rep;
    unsigned long sender;
    seminix_message_t recv_mess;

    ret = __syscall(SYS_seminix_RecvIPC, ep, IPC_NBRECV, &recv_mess, &rep, &sender, NULL);
    if (ret)
        return ret;

    if (reply)
        *reply = rep;
    if (badge)
        *badge = sender;
    if (mess)
        *mess = recv_mess;
    return ret;
}

int seminix_reply(int ep, unsigned long badge, seminix_message_t mess)
{
    return __syscall(SYS_seminix_ReplyIPC, ep, badge, mess);
}
